﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DevComponents.DotNetBar;
using DevComponents.DotNetBar.Controls;
using DevComponents.Editors;
using DevComponents.Editors.DateTimeAdv;
using Kugar.Core.Collections;
using Kugar.Core.WinForm;
using Kugar.ERPFramework.ClientBroker;
using Kugar.ERPFramework.Entity;
using Kugar.Core.ExtMethod;

namespace Kugar.ERPFramework.View.WinForm
{
    /// <summary>
    ///     通用取数窗体的基类
    /// </summary>
    public partial class ModuleDataFetcherBase : ModuleDataEditorBase, IDataFetcherForm
    {
        private static BindingListEx<Entity.EntityBase> _cacheRecentlyList = new BindingListEx<EntityBase>();
        private BindingListEx<Entity.EntityBase> _cacheList = new BindingListEx<EntityBase>();
        private bool _isLoadComplete = false;
        private int _currentPageIndex = 0;
        
        private FilterConditionCollection _conditionCollection = new FilterConditionCollection();
        private Color _defaultBackColor = Color.FromArgb(194, 217, 247);

        public ModuleDataFetcherBase()
        {
            InitializeComponent();

            InitFilterConditions();

            ApplyFilterConditionToControl();



            var columns = InitDataViewColumn();

            if (columns == null || columns.Count <= 0)
            {
                dgData.AutoGenerateColumns = true;
            }
            else
            {
                buildDataGridView(columns);
                dgData.AutoGenerateColumns = false;
            }

            _cacheList.Clear();

            dgData.AddRowIndex(true);
            dgData.DataSource = _cacheList;


        }

        /// <summary>
        ///     初始化过滤条件,所有需要添加的过滤条件,都需要在该函数中进行初始化,并添加到FilterConditions属性中
        ///    
        /// </summary>
        protected  virtual void InitFilterConditions()
        {

        }

        /// <summary>
        ///     初始化网格控件需显示的对应的列
        /// </summary>
        /// <returns>返回列配置,Key:对象属性名    value:对象属性类型</returns>
        protected virtual Dictionary<string,Type> InitDataViewColumn()
        {
            return null;
        }

        /// <summary>
        ///     将FilterConditions属性中设置的过滤条件,生成对应的控件<br/>
        ///     如需要添加自定义控件,可重载该函数以及GetConditionValue/SetConditionValue<br/>
        ///     并在本函数运行后,添加自定义处理
        /// </summary>
        protected virtual void ApplyFilterConditionToControl()
        {
            panFilterCondition.Controls.Clear();

            if (_conditionCollection.Count<=0)
            {
                return;
            }

            foreach (var condition in _conditionCollection)
            {
                var dataType = condition.Value.DataType;
                Control labelControl;
                Control editorControl;
                Control panel;
                var item = condition.Value;
                if (dataType == typeof(string))
                {
                    panel=BuildTextCondition(item.Text, out labelControl, out editorControl);
                }
                else if (dataType.IsNumericType())
                {
                    panel = BuildNumericCondition(item.Text, ((ConditionItem_Numeric)item).Digit, out labelControl, out editorControl);
                }
                else if (dataType == typeof (DateTime))
                {
                    panel = BuildDateTimeCondition(item.Text, ((ConditionItem_DateTime)item).ContainsTime, out labelControl,
                                              out editorControl);
                }
                else if (dataType.IsImplementlInterface(typeof(IEnumerable<>)) || dataType.IsImplementlInterface(typeof(IEnumerable)))
                {
                    panel = BuildListConditon(item.Text, ((ConditionItem_Enumable) item).Items, out labelControl,
                                              out editorControl);
                }
                else if (dataType == typeof (bool))
                {
                    panel = BuildBoolCondition(item.Text, out labelControl, out editorControl);
                }
                else
                {
                    continue;
                }

                item.Label = labelControl;
                item.Editor = editorControl;

                panFilterCondition.Controls.Add(panel);
            }
        }

        /// <summary>
        ///     根据传入的值,设置对应过滤控件的值
        /// </summary>
        /// <param name="conditionValue"></param>
        protected virtual void  SetConditionValue(Dictionary<string, object> conditionValue)
        {
            if (!EnableConditions)
            {
                return ;
            }

            foreach (var condition in FilterConditions)
            {
                var value =conditionValue==null?null:conditionValue.TryGetValue(condition.Value.Name,null);

                setControlValue(condition.Value.Editor, value);
            }

        }

        /// <summary>
        ///     获取过滤条件的值
        /// </summary>
        /// <returns></returns>
        protected virtual Dictionary<string, object> GetConditionValue()
        {
            if (!EnableConditions)
            {
                return null;
            }

            var ret = new Dictionary<string, object>();

            foreach (var condition in FilterConditions)
            {
                var value = getControlValue(condition.Value.Editor);

                ret.Add(condition.Key, value);
            }

            return ret;
        }

        /// <summary>
        ///     分页获取数据选取器的数据
        /// </summary>
        /// <param name="pageIndex">页码,从0开始</param>
        /// <param name="pageSize">分页大小</param>
        /// <returns></returns>
#if DEBUG
        protected virtual IEnumerable<Entity.EntityBase> GetData(int pageIndex, int pageSize)
#else
        protected  abstract  IEnumerable<Entity.EntityBase> GetData(int pageIndex, int pageSize)
#endif
        {
            return null;
        }

        /// <summary>
        ///     查询条件列表
        /// </summary>
        [Browsable(false)]
        protected FilterConditionCollection FilterConditions { get { return _conditionCollection; } }

        /// <summary>
        ///     是否允许显示过滤条件
        /// </summary>
        [DefaultValue(true)]
        [Browsable(true)]
        public  bool EnableConditions
        {
            get { return panLeft.Visible; }
            set 
            {
                panLeft.Visible = value;
                expandableSplitter1.Visible = value;
            }
        }

        /// <summary>
        ///     是否允许多选
        /// </summary>
        [Browsable(true)]
        [DefaultValue(true)]
        public bool MultiSelect
        {
            get { return dgData.MultiSelect; }
            set { dgData.MultiSelect = value; }
        }

        /// <summary>
        ///     分页每次读取的数据量
        /// </summary>
        [DefaultValue(20)]
        [Browsable(true)]
        public int PageSize { set; get; }


        /// <summary>
        ///     读取数据的当前页码
        /// </summary>
        [Browsable(false)]
        protected int CurrentPageIndex { get { return _currentPageIndex; } }

        /// <summary>
        ///     返回选中项
        /// </summary>
        [Browsable(false)]
        public EntityBase[] SelectItems
        {
            get
            {
                if (dgData.SelectedRows.Count<=0)
                {
                    return null;
                }
                else
                {
                    return
                        dgData.SelectedRows.AsEnumerable<DataGridViewRow>().Select(x => x.DataBoundItem).Cast(x => (EntityBase) x).ToArray();
                }
            }
        }



        /// <summary>
        ///     是否允许记录最近选择项
        /// </summary>
        [Browsable(true)]
        [DefaultValue(false)]
        protected bool EnableCacheRecently { get; set; }

        #region 创建不同数据类型的条件框
        private Control BuildTextCondition(string text, out Control label,out Control editor)
        {
            var panel = buildPanel();

            label = buildLabel(text);
            label.Location = new Point(4, 6);

            panel.Controls.Add(label);

            editor = buildTextBox();
            editor.Location = new Point(17, 22);

            panel.Controls.Add(editor);

            return panel;
        }

        private Control BuildNumericCondition(string text, int digit, out Control label, out Control editor)
        {
            var panel = buildPanel();

            label = buildLabel(text);
            label.Location = new Point(4, 6);

            panel.Controls.Add(label);

            editor = buildNumericBox(digit);
            editor.Location = new Point(17, 22);

            panel.Controls.Add(editor);

            return panel;
        }

        private Control BuildDateTimeCondition(string text, bool containsTime, out Control label, out Control editor)
        {
            var panel = buildPanel();

            label = buildLabel(text);
            label.Location = new Point(4, 6);

            panel.Controls.Add(label);

            editor = buildDateTimeBox(containsTime);
            editor.Location = new Point(17, 22);

            panel.Controls.Add(editor);

            return panel;
        }

        private Control BuildListConditon(string text, List<ComboItemEx> values, out Control label,out Control editor)
        {
            var panel = buildPanel();

            label = buildLabel(text);
            label.Location = new Point(4, 6);

            panel.Controls.Add(label);

            editor = buildComboBox(values);
            editor.Location = new Point(17, 22);

            panel.Controls.Add(editor);

            return panel;
        }
        
        private Control BuildBoolCondition(string text, out Control label, out Control editor)
        {
            var panel = buildPanel();

            label = null;

            editor = buildCheckBox();
            editor.Location = new Point(4, 6);

            panel.Controls.Add(editor);
            panel.Size = new Size(190, 28);

            return panel;
        }
        #endregion

        #region 创建条件所需的控件
        private Control buildPanel()
        {
            var panel = new Panel();

            panel.Width = 190;
            panel.Height = 48;
            panel.BackColor = _defaultBackColor;

            return panel;
        }

        private Control buildLabel(string text)
        {
            var label = new LabelX();

            label.Text = text;
            label.BackColor = _defaultBackColor;
            label.AutoSize = true;
            label.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0);

            return label;
        }

        private Control buildTextBox()
        {
            var textbox = new TextBoxX();

            textbox.Size = new Size(166, 21);
            textbox.Margin = new System.Windows.Forms.Padding(3, 3, 3, 3);

            return textbox;
        }

        private Control buildNumericBox(int digit)
        {
            if (digit<=0)
            {
                var textbox = new IntegerInput();
                textbox.Size = new Size(166, 21);
                textbox.Margin = new System.Windows.Forms.Padding(3, 3, 3, 3);
                textbox.ButtonClear.Visible = true;
                return textbox;
            }
            else
            {
                var textbox = new DoubleInput();

                textbox.Size = new Size(166, 21);
                textbox.Margin = new System.Windows.Forms.Padding(3, 3, 3, 3);
                textbox.DisplayFormat = "f" + digit;
                textbox.ButtonClear.Visible = true;
                return textbox;
            }

            
        }

        private Control buildDateTimeBox(bool isContainsTime)
        {
            var textbox = new DateTimeInput();

            textbox.Size = new Size(166, 21);
            textbox.Margin = new System.Windows.Forms.Padding(3, 3, 3, 3);
            textbox.ButtonClear.Visible = true;
            textbox.CustomFormat = "yyyy-MM-dd " +( isContainsTime ? "" : "HH:mm");

            return textbox;
        }

        private Control buildComboBox(List<Kugar.Core.WinForm.ComboItemEx> values)
        {
            var cmb = new ComboBoxEx();

            for (int i = 0; i < values.Count; i++)
            {
                cmb.Items.Add(values[i]);
            }

            cmb.Size = new Size(166, 21);
            cmb.Margin = new System.Windows.Forms.Padding(3, 3, 3, 3);
            cmb.DropDownStyle =ComboBoxStyle.DropDownList;
            cmb.SelectedIndex = 0;

            return cmb;
        }

        private Control buildCheckBox()
        {
            var chk = new CheckBoxX();

            chk.Size = new Size(88, 16);
            chk.Margin = new System.Windows.Forms.Padding(3, 3, 3, 3);
            chk.AutoSize = true;
            return chk;
        }
        #endregion

        #region 控件事件处理函数

        private void dgData_DataNeed(object sender, EventArgs e)
        {
            if (_isLoadComplete)
            {
                return;
            }

            var pageSize = PageSize;

            if (_currentPageIndex==0)
            {
                _isLoadComplete = false;
                pageSize = pageSize*2;
            }

            _currentPageIndex = _currentPageIndex += 1;

            var data = GetData(_currentPageIndex, pageSize);

            if (data==null || data.Any())
            {
                _isLoadComplete = true;
            }
            else
            {
                _cacheList.AddRange(data);
                dgData.Refresh();
            }
        }

        private void btnFilter_Click(object sender, EventArgs e)
        {
            _isLoadComplete = false;
            _cacheList.Clear();
            GetData(0, PageSize);
        }

        private void btnReset_Click(object sender, EventArgs e)
        {
            SetConditionValue(null);
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            if (dgData.SelectedRows.Count<=0)
            {
                MessageBox.Show("请选择数据");
            }
            else
            {
                if (EnableCacheRecently)
                {
                    var selectItems = SelectItems;

                    _cacheRecentlyList.AddRange(selectItems);
                }

                this.DialogResult=DialogResult.OK;
            }
        }

        #endregion

        /// <summary>
        ///     根据传入的控件,返回控件值
        /// </summary>
        /// <param name="editor"></param>
        /// <returns></returns>
        private object getControlValue(Control editor)
        {
            if (editor is TextBoxX)
            {
                return string.IsNullOrWhiteSpace(editor.Text) ? null : "";
            }
            else if (editor is CheckBoxX)
            {
                return ((CheckBoxX)editor).Checked;
            }
            else if (editor is ComboBoxEx)
            {
                return ((ComboItemEx)((ComboBoxEx)editor).SelectedItem).Value;
            }
            else if (editor is IntegerInput)
            {
                return ((IntegerInput)editor).ValueObject;
            }
            else if (editor is DoubleInput)
            {
                return (decimal)((DoubleInput)editor).ValueObject;
            }
            else if (editor is DateTimeInput)
            {
                return ((DateTimeInput)editor).ValueObject;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        ///     根据传入值,设置控件值
        /// </summary>
        /// <param name="editor"></param>
        /// <returns></returns>
        private void setControlValue(Control editor, object value)
        {
            if (editor is TextBoxX)
            {
                editor.Text = value.ToStringEx();
            }
            else if (editor is CheckBoxX)
            {
                ((CheckBoxX)editor).Checked = value == null ? false : (bool)value;
            }
            else if (editor is ComboBoxEx)
            {
                var cmb = (ComboBoxEx)editor;

                foreach (ComboItemEx item in cmb.Items)
                {
                    if (item.Value == value)
                    {
                        cmb.SelectedItem = item;
                    }
                }
            }
            else if (editor is IntegerInput)
            {
                ((IntegerInput)editor).ValueObject = value;
            }
            else if (editor is DoubleInput)
            {
                ((DoubleInput)editor).ValueObject = value;
            }
            else if (editor is DateTimeInput)
            {
                ((DateTimeInput)editor).ValueObject = value;
            }
            else
            {
                //return null;
            }
        }

        private void buildDataGridView(Dictionary<string, Type> columnConfig)
        {
            foreach (var config in columnConfig)
            {
                DataGridViewColumn column = new Kugar.UI.WinForm.DataGridViewDynamicCellTypeColumn();

                column.DataPropertyName = config.Key;
                column.Name = config.Key.Replace('.', '_');
                column.Width = 120;
                dgData.Columns.Add(column);
            }
        }



        public bool Show(Dictionary<string, object> initValue)
        {
            SetConditionValue(initValue);

            btnFilter_Click(this, EventArgs.Empty);

            return ShowDialog()==DialogResult.OK;
        }
    }


}
